package IC.Parser;


import java_cup.runtime.*;


%%

%class Lexer
%public
%function next_token
%type Token
%line
%scanerror LexicalError
%cup

%state TRADITIONAL_COMMENT
%state STRING

%{
  StringBuffer string = new StringBuffer();
%}

/* Macros */

LOWER_ALPHA=[a-z]
UPPER_ALPHA=[A-Z]
ALPHA={LOWER_ALPHA} | {UPPER_ALPHA} | [_]
DIGIT=[0-9]
ALPHA_NUMERIC={ALPHA}|{DIGIT}
CLASS_IDENT={UPPER_ALPHA}({ALPHA_NUMERIC})*
IDENT={LOWER_ALPHA}({ALPHA_NUMERIC})*
NUMBER=0+|[1-9][0-9]*

NEWLINE = \r|\n|\r\n
WHITESPACE = {NEWLINE}|[ \t\f]


EOL_COMMENT     = "//" [^\r\n]* {NEWLINE}
StringCharacter = [^\r\n\"\\]

%eofval{
	if (yystate() == TRADITIONAL_COMMENT) throw new LexicalError("Unclosed comment", yyline);
  	return new Token(sym.EOF, yyline);
%eofval}

%%
<YYINITIAL>
{
  /* ignore list */
  {EOL_COMMENT}                 { }
  "/*"							{ yybegin(TRADITIONAL_COMMENT); }
  {WHITESPACE}                  { }
}

/* keywords */
<YYINITIAL> "boolean"           { return new Token(sym.BOOLEAN, yyline, yytext()); }
<YYINITIAL> "break"             { return new Token(sym.BREAK, yyline, yytext()); }
<YYINITIAL> "class"             { return new Token(sym.CLASS, yyline, yytext()); }
<YYINITIAL> "continue"          { return new Token(sym.CONTINUE, yyline, yytext()); }
<YYINITIAL> "extends"           { return new Token(sym.EXTENDS, yyline, yytext()); }
<YYINITIAL> "if"             	{ return new Token(sym.IF, yyline, yytext()); }
<YYINITIAL> "else"             	{ return new Token(sym.ELSE, yyline, yytext()); }
<YYINITIAL> "false"             { return new Token(sym.FALSE, yyline, yytext()); }
<YYINITIAL> "int"             	{ return new Token(sym.INT, yyline, yytext()); }
<YYINITIAL> "length"            { return new Token(sym.LENGTH, yyline, yytext()); }
<YYINITIAL> "new"             	{ return new Token(sym.NEW, yyline, yytext()); }
<YYINITIAL> "null"             	{ return new Token(sym.NULL, yyline, yytext()); }
<YYINITIAL> "return"            { return new Token(sym.RETURN, yyline, yytext()); }
<YYINITIAL> "static"            { return new Token(sym.STATIC, yyline, yytext()); }
<YYINITIAL> "string"            { return new Token(sym.STRING, yyline, yytext()); }
<YYINITIAL> "this"             	{ return new Token(sym.THIS, yyline, yytext()); }
<YYINITIAL> "void"             	{ return new Token(sym.VOID, yyline, yytext()); }
<YYINITIAL> "true"             	{ return new Token(sym.TRUE, yyline, yytext()); }
<YYINITIAL> "while"            	{ return new Token(sym.WHILE, yyline, yytext()); } 

<YYINITIAL> "," 	            { return new Token(sym.COMMA, yyline, yytext()); }
<YYINITIAL> "."     	        { return new Token(sym.DOT, yyline, yytext()); }
<YYINITIAL> ">"         	    { return new Token(sym.GT, yyline, yytext()); }
<YYINITIAL> ">="                { return new Token(sym.GTE, yyline, yytext()); }
<YYINITIAL> "&&"             	{ return new Token(sym.LAND, yyline, yytext()); }
<YYINITIAL> "["            	 	{ return new Token(sym.LB, yyline, yytext()); }
<YYINITIAL> "{"             	{ return new Token(sym.LCBR, yyline, yytext()); }
<YYINITIAL> "]"            		{ return new Token(sym.RB, yyline, yytext()); }
<YYINITIAL> "!"             	{ return new Token(sym.LNEG, yyline, yytext()); }
<YYINITIAL> "||"           		{ return new Token(sym.LOR, yyline, yytext()); }
<YYINITIAL> "<"             	{ return new Token(sym.LT, yyline, yytext()); }
<YYINITIAL> "<="           		{ return new Token(sym.LTE, yyline, yytext()); }
<YYINITIAL> "%"             	{ return new Token(sym.MOD, yyline, yytext()); }
<YYINITIAL> "!="             	{ return new Token(sym.NEQUAL, yyline, yytext()); }
<YYINITIAL> ";"             	{ return new Token(sym.SEMI, yyline, yytext()); }
<YYINITIAL> "}"             	{ return new Token(sym.RCBR, yyline, yytext()); }
<YYINITIAL> "("             	{ return new Token(sym.LP, yyline, yytext()); }
<YYINITIAL> ")"             	{ return new Token(sym.RP, yyline, yytext()); }

<YYINITIAL> 
{	
   \"                             { yybegin(STRING); string.setLength(0); }
   
  /* operators */
  "="                           { return new Token(sym.ASSIGN, yyline, yytext()); }
  "=="                          { return new Token(sym.EQUAL, yyline, yytext()); }
  "+"                           { return new Token(sym.PLUS, yyline, yytext()); }
  "-"							{ return new Token(sym.MINUS, yyline, yytext()); }
  "*"							{ return new Token(sym.MULTIPLY, yyline, yytext()); }
  "/"							{ return new Token(sym.DIVIDE, yyline, yytext()); }	

  /* identifiers */ 
  ({DIGIT})+({ALPHA})+({ALPHA_NUMERIC})*	{ throw new LexicalError("Illegal identifier, id cannot start with a number" , yyline, yytext());}
  {CLASS_IDENT}           	    { return new Token(sym.CLASS_ID, yyline, yytext()); }
  {IDENT}						{ return new Token(sym.ID, yyline, yytext()); }
 
  /* literals */
  0+[1-9]+						{ throw new LexicalError("Illegal integer, int cannot start with zeroes" , yyline, yytext());}
  {NUMBER}			            { return new Token(sym.INTEGER, yyline, yytext()); }

  /* error fallback */
  .|\n  							{ throw new LexicalError("Illegal character", yyline, yytext()); }
}

<TRADITIONAL_COMMENT> 
{
	[^\*] 						{ }
	 "*/" 						{ yybegin(YYINITIAL); } 
	 "*" 						{ } 
}	

<STRING> {
  \"                             { yybegin(YYINITIAL); return new Token(sym.QUOTE, yyline,string.toString()); }
  
  {StringCharacter}+             { string.append( yytext() ); }
  
  /* escape sequences */
  "\\b"                          { string.append( "\b" ); }
  "\\t"                          { string.append( "\t" ); }
  "\\n"                          { string.append( "\n" ); }
  "\\f"                          { string.append( "\f" ); }
  "\\r"                          { string.append( "\r" ); }
  "\\\""                         { string.append( "\\\"" ); }
  "\\'"                          { string.append( "\'" ); }
  "\\\\"                         { string.append( "\\\\" ); }
  
  /* error cases */
  \\.                            { throw new LexicalError("Illegal escape sequence", yyline, yytext()); }
  {NEWLINE}             		 { throw new LexicalError("Unclosed quotes", yyline); }
}
